﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace ConstantCMapEditor3
{
    public class CommandManager
    {
        List<Command> DoList = new List<Command>();
        List<Command> UnDoList = new List<Command>();

        public void Execute(Command command)
        {
            UnDoList.Clear();
            DoList.Insert(0,command);
            if(DoList.Count>1000)DoList.RemoveAt(1000);
            command.Do();
        }

        public void Undo()
        {
            if (DoList.Count > 0) 
            {
                DoList[0].Undo();
                UnDoList.Insert(0, DoList[0]);
                DoList.RemoveAt(0);
            }
        }

        public void Redo() 
        {
            if (UnDoList.Count > 0)
            {
                UnDoList[0].Do();
                DoList.Insert(0, UnDoList[0]);
                UnDoList.RemoveAt(0);
            }
        }
    }

    public class ChangeLayerCommand : Command 
    {
        public ChangeLayerCommand(List<NormalSprite> spriteList, LayerState fromLayer,LayerState toLayer) 
        {
            _spriteList = spriteList;
             _toLayer = toLayer;
             _fromLayer = fromLayer;
        }

        List<NormalSprite> _spriteList;
        List<NormalSprite> _newList;
        LayerState _toLayer;
        LayerState _fromLayer;

        public List<Command> OriginDeleteCommand = new List<Command>();
        public List<Command> NewDeleteCommand = new List<Command>();

        override public void Do()
        {
            OriginDeleteCommand.Clear();

            foreach (NormalSprite s in _spriteList)
            {
                OriginDeleteCommand.Add(s.GetDeleteCommand());                     
            }

            foreach (Command c in OriginDeleteCommand)
            {
                c.Do();
            }

            ChangeTo(_toLayer);

            if (_newList == null || _newList.Count < 1)
            {
                _newList = new List<NormalSprite>();
                foreach (NormalSprite s in _spriteList)
                {
                    s.InstanceInit();
                    NormalSprite newSprite = (NormalSprite)Game1.declarationList[Game1.declarationList.Count - 1];
                    newSprite.LockAt32 = s.LockAt32;
                    newSprite.Mirror = s.Mirror;
                    newSprite.Position = s.Position;
                    newSprite.RotateR = s.RotateR;
                    _newList.Add(newSprite);
                    NewDeleteCommand.Add(newSprite.GetDeleteCommand());
                }
            }
            else 
            {
                foreach (Command c in NewDeleteCommand)
                {
                    c.Undo();
                }
            }
        }

        override public void Undo()
        {

            foreach (Command c in NewDeleteCommand)
            {
                c.Do();
            }


            ChangeTo(_fromLayer);



            foreach (Command c in OriginDeleteCommand)
            {
                c.Undo();
            }

        }

        private void ChangeTo(LayerState toLayer)
        {
            foreach (NormalSprite s in _spriteList)
            {
                s.UnFocus();
            }

            if (_newList!=null)
            foreach (NormalSprite s in _newList)
            {
                s.UnFocus();
            }

            Game1.SpriteEditorScene.LayerEditState = toLayer;

            switch(toLayer)
            {
                case LayerState.Layer1:
                    DeclarationDeocrator.Layer1.SpriteColor = DeclarationDeocrator.Layer2.SpriteColor = DeclarationDeocrator.Layer3.SpriteColor = DeclarationDeocrator.Layer4.SpriteColor = DeclarationDeocrator.Layer5.SpriteColor = Microsoft.Xna.Framework.Color.Gray;
                    DeclarationDeocrator.Layer1.SpriteColor = Microsoft.Xna.Framework.Color.White;
                    while (!Game1.SpriteEditorScene.ChangeView(1)) ;
                break;
                case LayerState.Layer2:
                DeclarationDeocrator.Layer1.SpriteColor = DeclarationDeocrator.Layer2.SpriteColor = DeclarationDeocrator.Layer3.SpriteColor = DeclarationDeocrator.Layer4.SpriteColor = DeclarationDeocrator.Layer5.SpriteColor = Microsoft.Xna.Framework.Color.Gray;
                DeclarationDeocrator.Layer2.SpriteColor = Microsoft.Xna.Framework.Color.White;
                    while (!Game1.SpriteEditorScene.ChangeView(2)) ;
                break;
                case LayerState.Layer3:
                DeclarationDeocrator.Layer1.SpriteColor = DeclarationDeocrator.Layer2.SpriteColor = DeclarationDeocrator.Layer3.SpriteColor = DeclarationDeocrator.Layer4.SpriteColor = DeclarationDeocrator.Layer5.SpriteColor = Microsoft.Xna.Framework.Color.Gray;
                    DeclarationDeocrator.Layer3.SpriteColor = Microsoft.Xna.Framework.Color.White;
                    while (!Game1.SpriteEditorScene.ChangeView(3)) ;
                break;
                case LayerState.Layer4:
                DeclarationDeocrator.Layer1.SpriteColor = DeclarationDeocrator.Layer2.SpriteColor = DeclarationDeocrator.Layer3.SpriteColor = DeclarationDeocrator.Layer4.SpriteColor = DeclarationDeocrator.Layer5.SpriteColor = Microsoft.Xna.Framework.Color.Gray;
                DeclarationDeocrator.Layer4.SpriteColor = Microsoft.Xna.Framework.Color.White;
                while (!Game1.SpriteEditorScene.ChangeView(4)) ;
                break;
                case LayerState.Layer5:
                DeclarationDeocrator.Layer1.SpriteColor = DeclarationDeocrator.Layer2.SpriteColor = DeclarationDeocrator.Layer3.SpriteColor = DeclarationDeocrator.Layer4.SpriteColor = DeclarationDeocrator.Layer5.SpriteColor = Microsoft.Xna.Framework.Color.Gray;
                DeclarationDeocrator.Layer5.SpriteColor = Microsoft.Xna.Framework.Color.White;
                while (!Game1.SpriteEditorScene.ChangeView(5)) ;
                break;
             } 
        }
    }

    public class BatchMirrorTransform : Command 
    {
        public BatchMirrorTransform(List<NormalSprite> targetList) 
        {
            
            _targetList = new List<NormalSprite>(targetList);
            foreach (NormalSprite d in _targetList) 
            {
                _previousPosition.Add(d.Position);
                _preLock.Add(d.LockAt32);
            }
        }

        override public void Do()
        {
            foreach (Declaration d in _targetList)
            {
                ((NormalSprite)d).LockAt32 = false;
                ((NormalSprite)d).ChangeMirrorState();
                d.RotateR = -d.RotateR;
                if (_targetList[0] == d) continue;
                Vector2 prePosition = d.Position - (_targetList[0]).Position;
                prePosition *= new Vector2(-1, 1);
                Vector2 newPosition = (_targetList[0]).Position - prePosition;


      

                d.Position = newPosition;
                
            }
        }

        override public void Undo()
        {
            for (int i = 0; i < _targetList.Count; i++) 
            {
                _targetList[i].Position = _previousPosition[i];
                _targetList[i].LockAt32 = _preLock[i];
                _targetList[i].ChangeMirrorState();
                _targetList[i].RotateR = -_targetList[i].RotateR;
            }
        }

        List<Vector2> _previousPosition = new List<Vector2>();
        List<Boolean> _preLock = new List<Boolean>();
        List<NormalSprite> _targetList;

    }

    public class BatchRotateTransform : Command 
    {
        public BatchRotateTransform(List<NormalSprite> targetList,double rotateR) 
        {
            
            _targetList = new List<NormalSprite>(targetList);
            _rotateR = rotateR;
            foreach (NormalSprite d in _targetList) 
            {
                _previousPosition.Add(d.Position);
                _previouseDouble.Add(d.RotateR);
                _preLock.Add(d.LockAt32);
            }
        }

        override public void Do()
        {
            foreach (Declaration d in _targetList)
            {
                d.RotateR += (float)_rotateR;
                ((NormalSprite)d).LockAt32 = false;
                if (_targetList[0] == d) continue;

                Vector2 prePosition = d.Position - (_targetList[0]).Position;
                Vector2 newPosition = (_targetList[0]).Position + Vector2.Transform(prePosition, Matrix.CreateRotationZ((float)_rotateR));
                d.Position = newPosition;
            }
        }

        override public void Undo()
        {
            for (int i = 0; i < _targetList.Count; i++) 
            {
                _targetList[i].Position = _previousPosition[i];
                _targetList[i].RotateR = (float)_previouseDouble[i];
                _targetList[i].LockAt32 = _preLock[i];
            }
        }

        List<Vector2> _previousPosition = new List<Vector2>();
        List<double> _previouseDouble = new List<double>();
        List<Boolean> _preLock = new List<Boolean>();

        List<NormalSprite> _targetList;
        double _rotateR;
    }

    public class MirrorCommand : Command 
    {
        public MirrorCommand(NormalSprite s) 
        {
            _s = s;
        }

        NormalSprite _s;

        override public void Do()
        {
            _s.ChangeMirrorState();
        }

        override public void Undo()
        {
            _s.ChangeMirrorState();
        }
    }

    public class ColorCommand : Command 
    {
        public ColorCommand(Scene s,Color c) 
        {
            _s = s;
            _c = c;
        }

        Color _c;
        Color _origin;
        Scene _s;

        override public void Do()
        {
            _origin = _s.SpriteColor;
            _s.SpriteColor = _c;
        }

        override public void Undo()
        {
            _s.SpriteColor = _origin;
        }
    }

    public class RotateCommand : Command
    {
        public RotateCommand(Declaration d,float targetRotate) 
        {
            _d = d;
            _f = targetRotate;
        }

        Declaration _d;
        float _f;
        float origin;

        override public void Do()
        {
            origin = _d.RotateR;
            _d.RotateR = _f;
        }

        override public void Undo()
        {
            _d.RotateR = origin;
        }
    }

    public class SpriteLockCommand : Command 
    {
        public SpriteLockCommand(NormalSprite sprite) 
        {
            target = sprite;
        }

        NormalSprite target;
        Boolean OriginLock;
        Vector2 Origin;

        override public void Do()
        {
            OriginLock = target.LockAt32;
            Origin = target.Position;
            target.LockAt32 = true;
        }

        override public void Undo()
        {
            target.LockAt32 = OriginLock;
            target.Position = Origin;
        }
    }

    public class SpriteUnLockCommand : Command
    {
        public SpriteUnLockCommand(NormalSprite sprite)
        {
            target = sprite;
        }

        NormalSprite target;
        Boolean OriginLock;
        Vector2 Origin;

        override public void Do()
        {
            OriginLock = target.LockAt32;
            Origin = target.Position;
            target.LockAt32 = false;
        }

        override public void Undo()
        {
            target.LockAt32 = OriginLock;
            target.Position = Origin;
        }
    }

    public class BatchCommand : Command
    {
        public BatchCommand(List<Command> commandList) 
        {
             _commandList = new List<Command>(commandList);
             commandList.Reverse();
             _rCommandList = new List<Command>(commandList);
           
        }

        List<Command> _commandList;
        List<Command> _rCommandList;

        override public void Do()
        {
            foreach (Command c in _commandList)
            {
                c.Do();
            }

        }

        override public void Undo()
        {
            foreach (Command c in _rCommandList)
            {
                c.Undo();
            }

        }

    }

    public class InvertCommand : Command 
    {
        public InvertCommand(Command command) 
        {
            InvertTarget = command;
        }

        Command InvertTarget;

        override public void Do()
        {
            InvertTarget.Undo();
        }

        override public void Undo()
        {
            InvertTarget.Do();
        }
    }

    public class BatchDeleteSpriteCommand : Command 
    {
        public BatchDeleteSpriteCommand(List<Declaration> all, List<Command> allCommand, List<Declaration> controlList) 
        {
            _all = all;
            _allCommand = allCommand;
            _controlList = controlList;
        }

        List<Declaration> _all;
        List<Command> _allCommand;
        List<Declaration> _controlList;

        override public void Do()
        {
            Game1.Selected = null;

            foreach (Command c in _allCommand)
            {
                c.Do();
            }

            _allCommand.Reverse();

            foreach (Declaration c in _all)
            {
                c.UnFocus();
            }

            _controlList.Clear();
        }

        override public void Undo()
        {
            Game1.Selected = null;

            foreach (Declaration c in _controlList)
            {
                c.UnFocus();
            }

            _controlList.Clear();

            foreach (Command c in _allCommand)
            {
                c.Undo();
            }

            _allCommand.Reverse();

            foreach (Declaration c in _all)
            {
                c.Focus();
                _controlList.Add(c);
            }
            Game1.Selected = null;
            ThreeLayerSpriteScene.Action = EditorAction.Move_Action;
        }
    }

    public class BatchMoveSpriteCommand : Command 
    {
        public BatchMoveSpriteCommand(List<Declaration> d, Vector2 Dif) 
        {
            _target = new List<Declaration>(d);
            _dif = Dif;
        }

        override public void Do() 
        {
            foreach(Declaration d in _target)
            {
            d.Position += _dif;
            }
        }

        override public void Undo() 
        {
            foreach(Declaration d in _target)
            {
            d.Position -= _dif;
            }
        }

        private List<Declaration> _target;
        private Vector2 _dif;
    }

    public class DeleteSpriteCommand : Command 
    {
        public DeleteSpriteCommand(NormalSprite target, List<LineHolder> lineList, List<Declaration> declarationList, Scene layer, PositionChecker positionChecker,bool selected)
        {
            _lineList = lineList;
            _declarationList = declarationList;
            _layer = layer;
            _target = target;
            _positionChecker = positionChecker;
            _selected = selected;
        }

        bool _selected;

        public DeleteSpriteCommand(NormalSprite target,List<LineHolder> lineList,List<Declaration> declarationList,Scene layer,PositionChecker positionChecker)
        {
            _lineList = lineList;
            _declarationList = declarationList;
            _layer = layer;
            _target = target;
            _positionChecker = positionChecker;
            _selected = true;
        }

        List<LineHolder> _lineList;
        List<Declaration> _declarationList;
        Scene _layer;
        PositionChecker _positionChecker;
        NormalSprite _target;

        int index  = 0;
        int index2 = 0;

        public override void Do()
        {
            index2 = _lineList.IndexOf(_target);
            _lineList.Remove(_target);
            _declarationList.Remove(_target);
            index = _layer.DettachChildReturnIndex(_target.sprite);
            _positionChecker.UnRegisterPosition(_target.prePosition);
            Game1.Selected = null;
        }

        public override void Undo()
        {
            _lineList.Insert(index2,_target);
            _declarationList.Add(_target);
            _layer.AttachChild(_target.sprite,index);
            _positionChecker.RegisterPosition(_target.prePosition);


            if (_selected)Game1.Selected = _target;
        }
    }

    public class MoveCommand : Command
    {
        public MoveCommand(Declaration d, Vector2 Dif) 
        {
            _target = d;
            _dif = Dif;
        }

        override public void Do() 
        {
            _target.Position += _dif;
        }

        override public void Undo() 
        {
            _target.Position -= _dif;
        }

        private Declaration _target;
        private Vector2 _dif;
    }

    abstract public class Command
    {
        abstract public void Do();
        abstract public void Undo();
    }
}
